package com.foreveross.crawl.adapter.sub.impl20140402.v3.travelsky;

import java.util.List;

import org.apache.http.client.methods.HttpPost;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.adapter.sub.impl20140402.v3.TravelskyAdapter;
import com.foreveross.crawl.common.util.RegHtmlUtil;
import com.foreveross.crawl.domain.airfreight.AbstractPlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.TransitEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnCabinEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnDoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.single.SinglePlaneInfoEntity;
import com.foreveross.crawl.exception.FlightInfoNotFoundException;
import com.foreveross.taskservice.common.bean.TaskModel;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

/**
 * 奥凯航空适配器 http://bk.travelsky.com/bkair/index.jsp
 * 
 * @author lijianning （mingliangluo重写于2014-08-05重写。）
 * @date 2014-05-22
 * @version 1.0v
 */
public class TravelskyInlandRoundAdapter extends TravelskyAdapter {

	/** ******************************** Constructor *********************************************** */
	public TravelskyInlandRoundAdapter(TaskModel taskQueue) {
		super(taskQueue);
	}

	/** ******************************** Params *********************************************** */

	/** ******************************** Fetch *********************************************** */

	@Override
	public String getUrl() throws Exception {
		StringBuffer sb = new StringBuffer("http://bk.travelsky.com/bkair/reservation/specialFlightQuery.do?");
		sb.append("tripType=1");//.append(taskQueue.getIsReturn());
		sb.append("&orgCity=").append(taskQueue.getFromCity());
		sb.append("&destCity=").append(taskQueue.getToCity());
		sb.append("&returnDate=").append(taskQueue.getFlightDate());
		sb.append("&takeoffDate=").append(taskQueue.getFlightDate());
		sb.append("&queryFlightRequestId=").append(requestId);
		return sb.toString();
	}

	/**
	 * 抓取页面数据 。
	 * 
	 * @return
	 * @throws Exception
	 */
	public Object fetch() throws Exception {
		String page = null;
		try {
			this.setCookie();
			page = super.excuteRequest(new HttpPost(getUrl()));
			validateFetch(page); // 验证
			super.setLenghtCount(page.getBytes().length);
			super.appendPageContents(page);
			queryPage = imageUtils.htmlPage(getUrl()); // 保存一下HttpPage，以便解析价格
			rollbackProxyIp(true);
		} catch (Exception e) {
			rollbackProxyIp(false);
			logger.error(String.format("页面数据抓取失败 ：%s", e.getMessage()));
			throw e;
		} finally {}
		return page;
	}

	/** ******************************** Parse *********************************************** */

	/** 往返程数据解析 */
	public Object parse(Object fetchObject) throws Exception {
		List<AbstractPlaneInfoEntity> toFlights = Lists.newArrayList();
		List<AbstractPlaneInfoEntity> backFlights = Lists.newArrayList();
		String page = fetchObject.toString();
		try {
			Document document = Jsoup.parse(page);
			Element goElems = document.getElementById("go_result_table");
			toFlights = parsePlaneInfos(false, goElems); // 去程航班集合

			/** * * * * * * 解析推荐联程 * * * * * * * * * * * * */
			// Element interElems = document.getElementById("rt_inter_result_table"); // 解析推荐联程
			// toFlights.addAll(parseInterPlaneInfos(interElems)); // 如果又有自由组合又有推荐联程，则两个合并。
			// PlaneInfoEntityBuilder.buildLimitPrice(toFlights);

			/** * * * * * * 回程 * * * * * * * * * * * * */
			Element reElems = document.getElementById("return_result_table");
			backFlights = parsePlaneInfos(true, reElems); // 回程航班集合

			for (AbstractPlaneInfoEntity goFlight : toFlights) {
				for (AbstractPlaneInfoEntity backFlight : backFlights) {
					PlaneInfoEntityBuilder.getDoubleEntity(goFlight).getReturnPlaneInfos().add(PlaneInfoEntityBuilder.getReturnDoubleEntity(backFlight));
				}
			}
			PlaneInfoEntityBuilder.buildRelation(toFlights, backFlights); // 设置关系
			PlaneInfoEntityBuilder.buildLimitPrice(toFlights); // 价格排序
		} catch (Exception e) {
			logger.error("数据解析出错 ： " + e.getMessage());
			throw e;
		}
		return toFlights;
	}

	/**
	 * 解析职程航班 。
	 * 
	 * @return
	 * @throws Exception
	 */
	private List<AbstractPlaneInfoEntity> parseInterPlaneInfos(Element elem) throws Exception {

		List<String> flightNos = null;
		List<String> flightDates = null;
		List<String> fromCitys = null;
		List<String> fromTimes = null;
		List<String> toCitys = null;
		List<String> endTimes = null;
		List<String> types = null;

		Elements trs = elem.getElementsByTag("tr");

		for (int i = 0; i < trs.size(); i++) { // 1 4 7 11航班行
			SinglePlaneInfoEntity planeInfo = null;

			Elements tds = trs.get(i).getElementsByTag("td");

			Elements flightNoElems = tds.get(0).getElementsByTag("img");
			flightNos = ImmutableList.of(parseImg(flightNoElems.get(0), "1"), parseImg(flightNoElems.get(1), "1"));
			flightDates = RegHtmlUtil.regStrs(tds.get(1).text(), "\\s*(.*?)<br/>\\s*(.*?)\\s*"); // 航班日期S
			fromCitys = RegHtmlUtil.regStrs(tds.get(2).text(), "(.+?)[.*?]\\s*?<br/>\\s*?(.+?)[");// 起飞城市
			Elements fromCityElems = tds.get(2).getElementsByTag("img");
			fromTimes = ImmutableList.of(parseImg(fromCityElems.get(0), "1"), parseImg(fromCityElems.get(1), "1"));// 起飞时间
			fromCitys = RegHtmlUtil.regStrs(tds.get(3).text(), "(.+?)[.*?]\\s*?<br/>\\s*?(.+?)[");// 降落城市
			Elements toCityElems = tds.get(3).getElementsByTag("img");
			endTimes = ImmutableList.of(parseImg(toCityElems.get(0), "1"), parseImg(toCityElems.get(1), "1"));// 降落时间
			types = RegHtmlUtil.regStrs(tds.get(4).text(), "\\s*(.*?)<br/>\\s*(.*?)\\s*");

			planeInfo = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, "BK", "奥凯", "奥凯航空", null, null, flightNos.get(0), null, null, null, types.get(0), SinglePlaneInfoEntity.class);
			planeInfo.setStartTime(PlaneInfoEntityBuilder.getFlightTime(flightDates.get(0), fromTimes.get(0)));
			planeInfo.setStartTime(PlaneInfoEntityBuilder.getFlightTime(flightDates.get(flightDates.size() - 1), endTimes.get(endTimes.size() - 1)));

			List<TransitEntity> trans = Lists.newArrayList();
			for (int j = 0; j < flightNoElems.size(); j++) {
				TransitEntity tran = PlaneInfoEntityBuilder.buildTransitEntity(flightNos.get(j), flightNos.get(j), "BK", "奥凯", "奥凯航空", null, fromCitys.get(j), null, toCitys.get(j), types.get(j));
				trans.add(tran);
			}

			List<CabinEntity> cabins = getInterCabins(false, tds.get(6)); // 最低舱位。
			List<CabinEntity> moreCabins = getInterCabins(false, trs.get(i + 1)); // 更多舱位。

			planeInfo.getCabins().addAll(cabins);
			planeInfo.getCabins().addAll(moreCabins);
		}

		return null;
	}

	/** 解析出航班信息。 */
	private List<AbstractPlaneInfoEntity> parsePlaneInfos(Boolean isReturn, Element elem) throws Exception {
		List<AbstractPlaneInfoEntity> planeInfos = Lists.newArrayList();

		Elements trs = elem.getElementsByTag("tr");
		for (int i = 0; i < trs.size(); i++) { // 1 4 7 11航班行
			if (i % 3 != 1) continue;
			AbstractPlaneInfoEntity planeInfo = null;

			Element tr = trs.get(i);
			Elements tds = tr.getElementsByTag("td");
			String flightNo = parseImg(tds.get(0), "1");// 航班号
			String depTime = parseImg(tds.get(1), "2");// 起飞时间
			String arrTime = parseImg(tds.get(2), "2");// 到达时间
			String type = tds.get(4).text();

			// 回程，去程
			if (isReturn) {
				planeInfo = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, "BK", "奥凯", "奥凯航空", depTime, arrTime, flightNo, null, null, null, type, ReturnDoublePlaneInfoEntity.class);
				List<ReturnCabinEntity> cabins = getCabins(isReturn, tds.get(5), tds.get(6), tds.get(7), tds.get(8));
				List<ReturnCabinEntity> morecabins = getMoreCabins(trs.get(i + 1), isReturn); // 每个航班的更多舱位都在航班的后一行。
				cabins.addAll(morecabins);
				PlaneInfoEntityBuilder.getReturnDoubleEntity(planeInfo).getReturnCabins().addAll(cabins);
			} else {
				planeInfo = PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, "BK", " 奥凯", "奥凯航空", depTime, arrTime, flightNo, null, null, null, type);
				List<CabinEntity> cabins = getCabins(isReturn, tds.get(5), tds.get(6), tds.get(7), tds.get(8));
				List<CabinEntity> morecabins = getMoreCabins(trs.get(i + 1), isReturn); // 每个航班的更多舱位都在航班的后一行。
				cabins.addAll(morecabins);
				PlaneInfoEntityBuilder.getDoubleEntity(planeInfo).getCabins().addAll(cabins);
			}
			planeInfos.add(planeInfo);
		}
		return planeInfos;
	}

	/** 获取联程更多舱位。 */
	private <T> List<T> getInterCabins(Boolean isReturn, Element element) throws Exception {
		List<T> cabins = Lists.newArrayList();
		String reg = "interShowEI.*?\"([A-Z]{2})\".*?\"(.*?)\",\"(.*?)\").*?src=\"(.*?)\"";
		List<List<String>> lists = RegHtmlUtil.retrieveLinkss(element.toString(), reg);
		for (List<String> list : lists) {
			T cabin = null;
			String cabinName = list.get(1) + "舱";
			String tax = (PlaneInfoEntityBuilder.getDouble(list.get(2)) + PlaneInfoEntityBuilder.getDouble(list.get(3))) + ""; // 税费
			String price = parseImg(list.get(4), "0"); // 解析图片价格。
			if (isReturn) cabin = (T) PlaneInfoEntityBuilder.buildCabinInfo(cabinName, null, cabinName, tax, price, tax + price, null, null, ReturnCabinEntity.class);
			else cabin = (T) PlaneInfoEntityBuilder.buildCabinInfo(cabinName, null, cabinName, tax, price, tax + price, null, null, CabinEntity.class);
			cabins.add(cabin);
		}
		return cabins;
	}

	/** 获取舱位。 */
	private <T> List<T> getCabins(Boolean isReturn, Element... elements) throws Exception {
		List<T> cabins = Lists.newArrayList();
		for (int i = 0; i < elements.length; i++) {
			T cabin = null;
			Element ele = elements[i].select("td").first();
			if ("--".equals(ele.text())) continue; // 没有价格。
			Elements eles = ele.getAllElements();
			String cabinName = cabinNames.get(i);
			String subcabin = eles.get(1).attr("value").split("/")[2];
			String tuigaiqian = eles.get(1).attr("title");
			String price = parseImg(eles.get(2), "0");
			if (isReturn) cabin = (T) PlaneInfoEntityBuilder.buildCabinInfo(cabinName, subcabin, cabinName, null, price, null, tuigaiqian, null, ReturnCabinEntity.class);
			else cabin = (T) PlaneInfoEntityBuilder.buildCabinInfo(cabinName, subcabin, cabinName, null, price, null, tuigaiqian, null, CabinEntity.class);
			cabins.add(cabin);
		}
		return cabins;
	}

	/** 获取更多舱位。 */
	private <T> List<T> getMoreCabins(Element element, Boolean isReturn) throws Exception {
		List<T> cabins = Lists.newArrayList();
		String reg = "class=\"more\">.*?<b>(.*?)</b>.*?<img src=\"(.*?)\"";
		List<List<String>> lists = RegHtmlUtil.retrieveLinkss(element.toString(), reg);
		for (List<String> list : lists) {
			T cabin = null;
			String cabinName = list.get(1);
			String tuigaiqian = "";// list.get(2);
			String subcabin = cabinName.substring(0, 1);// list.get(3);
			String price = parseImg(list.get(2), "0");
			if (isReturn) cabin = (T) PlaneInfoEntityBuilder.buildCabinInfo(cabinName, subcabin, cabinName, null, price, null, tuigaiqian, null, ReturnCabinEntity.class);
			else cabin = (T) PlaneInfoEntityBuilder.buildCabinInfo(cabinName, subcabin, cabinName, null, price, null, tuigaiqian, null, CabinEntity.class);
			cabins.add(cabin);
		}
		return cabins;
	}

	@Override
	public boolean validateFetch(Object fetchObject) throws Exception {
		System.out.println("Round的验证 。");
		if (fetchObject == null) {
			throw new Exception("抓取到的数据为空！");
		}
		if (RegHtmlUtil.regMathcher(fetchObject.toString(), "公共的出错页面")) {
			throw new Exception("服务器忙，请稍后再试 ");
		}

		Document doc = Jsoup.parse(fetchObject.toString());
		Element ele1 = doc.getElementById("rt_inter_result_table");
		Element ele2 = doc.getElementById("go_result_table");
		// Element ele3 = doc.getElementById("return_result_table");

		String msg = "没有相应的航班";
		if (RegHtmlUtil.regMathcher(ele1.toString(), msg) && RegHtmlUtil.regMathcher(ele2.toString(), msg)) {
			throw new FlightInfoNotFoundException(msg);
		}
		return true;
	}
}